﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Migrator.Util;

namespace Migrator.Services.MobileAgents
{
    /// <summary>
    /// Mobility binding table, used by home agents
    /// </summary>
    public class BindingTable
    {
        /// <summary>
        /// Adds a new entry to the mobility binding table
        /// </summary>
        /// <param name="entry">The entry to add</param>
        /// <param name="replace">Replace previous entries?</param>
        public void Add(BindingEntry entry, bool replace)
        {
            if (!table.ContainsKey(entry.HomeAddress))
            {
                table[entry.HomeAddress] = new List<BindingEntry>();
            }

            if (replace)
            {
                table[entry.HomeAddress] = new List<BindingEntry>() { entry };
            }
            else
            {
                // If this is a duplicate, modify the previous entry
                var oldEntry = table[entry.HomeAddress].Where(old => old.CareOfAddress == entry.CareOfAddress).FirstOrDefault();
                if (oldEntry != null)
                {
                    oldEntry.ExpirationTime = entry.ExpirationTime;
                }
                else
                {
                    table[entry.HomeAddress].Add(entry);
                }
            }
        }

        public bool Contains(IPAddress homeAddress)
        {
            return this.table.ContainsKey(homeAddress);
        }

        public List<BindingEntry> this[IPAddress homeAddress]
        {
            get { return table[homeAddress]; }
        }

        /// <summary>
        /// Removes all entries for the given home address
        /// </summary>
        /// <param name="homeAddress">The home address to deregister</param>
        public void RemoveAll(IPAddress homeAddress)
        {
            this.table.Remove(homeAddress);
        }

        /// <summary>
        /// Removes the entry for the given care-of address.
        /// Note that other entries for the same home address are not removed.
        /// </summary>
        /// <param name="careOfAddress"The care-of address to deregister></param>
        public void Remove(IPAddress careOfAddress)
        {
            foreach (var entries in this.table.Values)
            {
                entries.RemoveAll(entry => entry.CareOfAddress == careOfAddress);
            }
        }

        /// <summary>
        /// Removes expired entries
        /// </summary>
        /// <param name="now">The current clock time</param>
        public void RemoveExpired(int now)
        {
            foreach (var entries in this.table.Values)
            {
                entries.RemoveAll(entry => entry.ExpirationTime < now);
            }
        }

        /// <summary>
        /// Mobility binding table
        /// </summary>
        private Dictionary<IPAddress, List<BindingEntry>> table = new Dictionary<IPAddress, List<BindingEntry>>();

        /// <summary>
        /// Mobility binding table entry
        /// </summary>
        public class BindingEntry
        {
            public BindingEntry(IPAddress homeAddress, IPAddress careOfAddress, int expirationTime)
            {
                this.HomeAddress = homeAddress;
                this.CareOfAddress = careOfAddress;
                this.ExpirationTime = expirationTime;
            }

            public IPAddress HomeAddress
            {
                get;
                private set;
            }

            public IPAddress CareOfAddress
            {
                get;
                private set;
            }

            public int ExpirationTime
            {
                get;
                set;
            }
        }

        public Dictionary<IPAddress, List<BindingEntry>> Table
        {
            get { return this.table; }
        }
    }
}
